#!d:\perl\bin\perl.exe
############################################################################
# $Id: TimeTrack.pl,v 1.9 2001/10/25 00:25:08 muquit Exp $
# A very simple fiel based CGI for tracking time working in a project
# Creates the a directory structure like below in the current working 
# directory. Change $project_dir if you want.
#
#   TimeTrack/
#   |-- Project1/
#   |   `-- Project1.dat
#   `-- Project2/
#   |   `-- Project2.dat
#   `-- Foo/
#   |   `--Foo.dat
#   |
#   `-- removed
#       `--project1_unix_epoch_secs
#       `--...
#
#  you got the idea.
#
# Format of the data file is:
#   - comment starts with #
#   _rate_=number tells the rate per hour
#  The data starts with _data_ in a new line and the data follows
# DATE<TAB>Start Time<TAB>End Time<TAB>Description
# <TAB> is the tab character.
# Example:
# # this is a comment
# _rate_=100.00
# _data_
# 8/15/2001<tab>9:30 PM<tab>10:15PM<tab>Fixed some bugs. blah blah
# 8/16/2001<tab>10:30 PM<tab>11:15PM<tab>Added feature foo. blah blah
#
#  The script is not fool proof. It doesn't do much checking on things. 
#  I try not to do stupid things. So if you decide to use it for some reasons,
#  don't do stupid things :) Also note, there's no security. If you use it
#  a public server, make sure you protect the cgi directory. At startup 
#  the script will allow you to create project and rest is self explanatory.
#  You won't be able to delete any created project from the interface, you've
#  delete the project directory yourself.
#
# 
#Copyright 2001 by Muhammad A Muquit (muquit@muquit.com).  Permission 
#to use, copy, modify and distribute this program is hereby granted without 
#fee, provided that this copyright notice appear in all copies and that 
#both that copyright notice and this permission notice appear in supporting 
#documentation.  If the source code of the program is modified or enhanced, 
#the source code must be made public and it must be clearly mentioned in 
#the documentation what was modified.
#
#THIS PROGRAM IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.  THE 
#AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 
#ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 
#THE AUTHOR Muhammad A. Muquit BE LIABLE FOR ANY SPECIAL, INDIRECT OR 
#CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 
#DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 
#TORTUOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
#PERFORMANCE OF THIS SOFTWARE.
#
#       
# muquit@muquit.com Aug-18-2001 
# muquit@muquit.com Oct-24-2001 - fixed some bugs
#############################################################################

use strict;
use CGI;
use CGI::Carp 'fatalsToBrowser';
use Time::Local;

######################### globals-------------- starts
my $version_s="1.2";
my $project_dir="./TimeTrack";
my $query;
my $path_info;
my $script_name;
my @month=("January","February","March","April","May","Jun","July",
        "August","Semtember","October","November","December");
######################### globals-------------- ends


$query=new CGI;
my $script_name=$query->script_name;
my $path_info=$query->path_info;

print $query->header;
print $query->start_html(
        -title=>"Simple Personal Project Time Tracking System",
        -bgcolor=>"#cccccc");

if ($query->param)
{
    &doWork();
}
else
{
    &printForms();
}

&creatProject() if ($path_info eq '/creat_project');
&newSession() if ($path_info eq '/new_session');
&saveSession() if ($path_info eq '/save_session');
&saveEditedData() if ($path_info eq '/save_edited_data');
&printAddProjectForm() if ($path_info eq '/new_project');
&restoreProject() if ($path_info eq '/unremove_project');
&aboutTimeTrack() if ($path_info eq '/about');
&aboutTimeTrack() if ($path_info eq '/author');

##-----
# doWork()
#------
sub doWork
{
    if (! $path_info)
    {
        &printForms();
    }
}


##-----
# printForms()
##-----
sub printForms
{

    my @projects=();
    my $p;

    $p=&getProjects();
    @projects=@$p;
    if (scalar(@projects))
    {
        if ($path_info ne '/new_project')
        {
            &printForm(\@projects);
        }
    }
    else
    {
#      &printAddProjectForm();
       &printForm(\@projects);
    }
    
}

##-----
# printForm()
##-----
sub printForm
{
    my $p=shift;
    my @projects=@$p;
    my $dir='';
    my @menu=();
    my @choices=("New Session","Edit","Report","Create Project", "Remove Project","Restore Projects");


    print $query->start_form(-action=>"$script_name/new_session");
    print "<table border cellpadding=2 cellspacing=1>\n";

    foreach $dir (@projects)
    {
        push(@menu,$dir);
    }
    print "<tr>\n";

    print<<EOF;
    <td nowrap colspan=2 align="center" bgcolor="#84bc7c">
    <font color="#000099">
    <b>Project TimeTrack</b>
    </font>
    <br
    </td>
    </tr>
EOF
;

    print "<tr>\n";
    print "<td nowrap>\n";
    if (scalar(@menu))
    {
            print "<b>Project:</b>\n";
            my $p=$query->param('project');
            print $query->popup_menu(-name=>'projects',-values=>\@menu,
                                 -default=>"$p");
    }
    else
    {
        print "-No Projects-\n";
    }
    print "</td>\n";
    print "<td>\n";
    print $query->radio_group(-name=>'choices',-values=>\@choices,
                              -linebreak=>'true',
                              -default=>$choices[0]);

    print "</td>\n";
    print "</tr>\n";

    print "<tr>\n";
    print "<td colspan=2 align=\"center\">\n";
    print $query->submit(-name=>'submit',-value=>'Submit');
    print "</td>\n";
    print "</tr>\n";

    print "</table>\n";
    print $query->end_form;
}

##-----
# printAddProjectForm()
##-----
sub printAddProjectForm
{
    print $query->start_form(-action=>"$script_name/creat_project");
    print "<table border cellpaddig=0 cellspacing=0>\n";

    print "<tr bgcolor=\"#99ccff\">\n";
    print "<td nowrap colspan=2 align=\"center\">\n";
    print "<b>Create Project</b><br>\n";
    print "<a href=\"$script_name\">Project session</a><br>\n";
    print "</td>\n";
    print "</tr>\n";

    print "<tr>\n";
    print "<td aligh=\"right\">\n";
    print "Project name:\n";
    print "</td>\n";

    print "<td>\n";
    print $query->textfield(-name=>'project',-size=>20);
    print "</td>\n";
    print "</tr>\n";

    print "<tr>\n";
    print "<td colspan=2 align=\"center\">\n";
    print $query->submit(-name=>'submit',-value=>'Create project');
    print "</td>\n";
    print "</tr>\n";


    print "</table>\n";
    print $query->end_form;
}

##----
# getProjects()
#   opens the $project_dir,directory, finds all the directories inside, 
#   and put the file #   names in an array and.
# note removed is a special directory, you can't have a project by
# that name
# returns reference the array 
##----
sub getProjects
{
    local
        *DIR;

    my @projects=();
    my @files=();

    if (! opendir(DIR,$project_dir))
    {
        if (!mkdir($project_dir,0700))
        {
            &printError("Could not make project directory: $project_dir ($!)");
            exit(0);
        }
    }

    @files=readdir(DIR);
    closedir(DIR);

    my $file;
    foreach $file (@files)
    {
        next if $file eq '.';
        next if $file eq '..';
        if (-d "${project_dir}/${file}") 
        {
            next if ($file eq "removed");
            push(@projects,$file);
        }
    }

    return (\@projects);
}

##-----
# printError()
##-----
sub printError
{
    my $em=shift;
    print <<EOF;
<font color="#ff0000" size="+1"><b>Error:</b></font><font size="+1"> $em</font>
<br>
EOF
;
#    print<<EOF;
#        <table border=0 bgcolor="#000000" cellpadding=0 cellspacing=0
#width="60%">
#        <tr>
#            <td>
#                <table border=0 width="100%" cellpadding=5 cellspacing=1>
#                    <tr">
#                        <td bgcolor="#ffefd5" width="100%">
#                        
#                        <font color="#ff0000"><b>Error -</b></font>
#                        $em</td>
#                    </tr>
#                </table>
#            </td>
#        </tr>
#            
#        </table>
#<p>
#EOF
#;
}

##-----
# creatProcect()
##-----
sub creatProject
{
    my $project=$query->param('project');
    my $save=$project;
    if (! $project)
    {
        &printError("No project name specified for adding");
        &printAddProjectForm();
        return;
    }
    if ($project =~ /\s+/)
    {
        &printError("Project name can not have space");
        return;
    }
    $project="${project_dir}/${project}";
    if (! mkdir($project))
    {
        &printError("Could not make directory: \"$project\" ($!)");
        return;
    }

    print "<font color=\"#00ff00\"><b>OK</b></font>: Project <b>$save</b> created<br>\n";
    &printForms();
}

##-----
# removeProject()
##-----
sub removeProject
{
    my $project=shift;
    my $save=$project;
    my $marked_del='';
    if (! $project)
    {
        &printError("No project name specified for removing");
        return;
    }
    my $file="${project_dir}/${project}/${project}.dat";
    my $pdir="${project_dir}/${project}";
    if (! -f $file)
    {
#        &printError("Nothing to remove! File <code>$file</code> does not exist");
    }
    my $del_dir="${project_dir}/removed";
    if (! -d $del_dir)
    {
        unless(mkdir($del_dir,0700))
        {
            &printError("Could not make directory: <code>$del_dir</code>");
            return;
        }
    }
    my $t=time();
    $marked_del="${del_dir}/${project}_$t";

    if (-f $file)
    {
        unless(rename($file,$marked_del))
        {
            &printError("Could not rename:<code>$file to $marked_del");
            return;
        }
    }

    if (-d "$pdir")
    {
        unless(rmdir("$pdir"))
        {
            &printError("Could not remove directory: <code>$pdir</code>");
            return;
        }
        print<<EOF;
<font color=\"#00ff00\"><b>OK:</b></font> 
Project <font color="#000099">$project</font> marked deleted
EOF
;

    }

    &printForms();

}

##-----
# newSession()
##-----
sub newSession
{
    my ($day,$month,$year)=(localtime)[3,4,5];
    $month++;
    $year += 1900;

    my $date="${month}/${day}/${year}";

    my $choice=$query->param('choices');
    my $project=$query->param('projects');

    if ($choice eq "Create Project")
    {
        &printAddProjectForm();
        return;
    }

    if (! &verifyProject($project))
    {
        &printError("<code>newSession():</code> No project found");
        &printForms();
        return;
    }

    if ($choice eq "Report")
    {
        &printReport($project);
        return;
    }

    if ($choice eq "Edit")
    {
        &editDataFile($project);
        return;
    }

    if ($choice eq "Remove Project")
    {
        &removeProject($project);
        return;
    }

    if ($choice eq "Restore Projects")
    {
        &restoreProjectsForm();
        return;
    }

    print $query->start_form(-action=>"$script_name/save_session");

    print $query->hidden('project',$project);

    print<<EOF;
Syntax for Time from and Time to is <code><b>Hr:Min AM/PM</b></code>. 
    <br>
     Example:<br>
        7:00 AM 10:34 PM 12:00 AM 12:00 PM etc.
<br>
<br>
EOF
;

    print "<table border cellpaddig=2 cellspacing=1>\n";

    print "<tr>\n";
    print "<td align=\"center\" bgcolor=\"#a0b8c8\" colspan=4>\n";
    print "<b>New session for project <font color=\"#00ff00\">$project</font></b>\n";
    print "</td>\n";
    print "</tr>\n";

    print "<tr>\n";
    print "<td nowrap>\n";
    print "Date:";
    print $query->textfield(-name=>'date',size=>10,-default=>"$date");
    print "</td>\n";

    print "<td nowrap>\n";
    print "Time from:";
    print $query->textfield(-name=>'time_from',-size=>10);

    print "</td>\n";

    print "<td nowrap>\n";
    print "Time to:";
    print $query->textfield(-name=>'time_to',-size=>10);
    print "</td>\n";

    print "<td nowrap>\n";
    print "Rate/hr:";
    print $query->textfield(-name=>'rate',-size=>10,-default=>"150.0");
    print "</td>\n";
    print "</tr>\n";


    print "<tr>\n";
    print "<td valign=\"top\" colspan=4>\n";
    print "Description:<br>\n";
    print $query->textfield(-name=>'comment',-size=>80);
    print "</td>\n";
    print "</tr>\n";

##    print "<tr>\n";
##    print "<td valign=\"top\" colspan=4>\n";
##    print "Trailer (HTML tag can be used):<br>\n";
##    print $query->textarea(-name=>'trailer',
##            -rows=>4,
##            -columns=>80);
##    print "</td>\n";
##    print "</tr>\n";

    print "<tr><td colspan=4 align=\"center\">\n";
    print $query->submit(-name=>'submit_new',-value=>'Submit');
    print "</td></tr>\n";


    print "</table>\n";
    print $query->end_form;
}

##-----
# saveSession()
##-----
sub saveSession
{
    my $errstr='';
    my $total_hr=0.0;
    my $amount=0.0;


    my $date=$query->param('date');
    my $time_from=$query->param('time_from');
    my $time_to=$query->param('time_to');
    my $rate=$query->param('rate');
    my $comment=$query->param('comment');

    if (! $date)
    {
        $errstr="No date specified<br>";
    }

    if (! $time_from)
    {
        $errstr .= "No Time from specified<br>";
    }

    if (! $time_to)
    {
        $errstr .= "No Time to specified<br>";
    }
    
    if (! $comment)
    {
        $errstr .= "No description specified";
    }

    if ($errstr)
    {
        &printError($errstr);
        &newSession();
        return;
    }
#    print "Project=",$query->param('project'),"<br>\n";
    my $project=$query->param('project');
    if (! &verifyProject($project))
    {
        &printError("No project found");
        &printForms();
        return;
    }
    &writeDataFile($rate,$date,$time_from,$time_to,$comment,$project);
}

##-----
# writeDataFile()
##-----
sub writeDataFile
{
    my $rate=shift;
    my $date=shift;
    my $time_from=shift;
    my $time_to=shift;
    my $comment=shift;
    my $project=shift;
    local *WFD;

#    print "writeDataFile Project=$project<br>\n";
    my $file="${project_dir}/${project}/${project}.dat";

    if (! parseTime($time_from))
    {
        &printError("Could not parse time: $time_from<br>The format is <b>Hr:Min AM/PM</b>, e.g 10:03 AM");
        return;
    }
    if (! parseTime($time_to))
    {
        &printError("Could not parse time: $time_to<br>The format is <b>Hr:Min AM/PM</b>, e.g 10:03 AM");
        return;
    }



    # TODO: Lock file before writing
    if (! -f $file)
    {
         unless (open(WFD,">$file"))
        {
            &printError("Could not open file for writing: $file ($!)");
            return;
        }
        print WFD "# data file for project: $project\n";
        print WFD "_rate_=$rate\n";
        print WFD "_data_\n";
    }
    else
    {
        unless (open(WFD,">>$file"))
        {
            &printError("Could not open file for writing: $file ($!)");
            return;
        }
    }

    print WFD "$date\t$time_from\t$time_to\t$comment\n";
    close(WFD);
    print "OK: wrote data successfully<br>\n";
    &printForms();
}

##-----
# printReport()
##-----
sub printReport
{
    my $project=shift;

    my $file="${project_dir}/${project}/${project}.dat";

    my $report=&genReport("$file");
    return if (! $report);
    my @reporta=@$report;
    my $line;
    my $g_rate=0.0;

print <<EOF;
<html>
<head>
    <title>Project work-hours</title>
</head>
<body>

EOF
;

if (scalar(@reporta))
{
    my $colspan=5;

    print <<EOF;
<table border=0 cellpadding=4 cellspacing=1 bgcolor="#87cefa">
<tr>
<td colspan=$colspan align="center" bgcolor="#a0b8c8">
<b><font color="#00ff00">$project</font> Project - work Hours
</td>
</tr>

<tr>

<td align="center">
<b>Date</b>
</td>

<td align="center">
<b>Description</b>
</td>


<td align="center">
<b>From</b>
</td>

<td align="center">
<b>To</b>
</td>


<td align="right">
<b>Hours</b>
</td>

</tr>
EOF
;
    foreach $line (@reporta)
    {
        print "<tr>\n";
        print "$line\n";
        print "</tr>\n";
    }
    print "</table>\n";
}
print <<EOF;
</body>
</html>
EOF
;
}

##-----
# genReport()
#  arg: the name of the file containing the data, format of the file is
#   comment starts with #
#   _rate_=n.0
#   _data_
# Date<tab>Hr:Min<tab>Hr:Min<tab>Comment
#
# returns reference to an array containing the report
##------
sub genReport
{
    my $file=shift;

    local *FD;
    my @report=();
    my $line='';
    my $rate=150.0;
    my ($date,$from,$to,$comment)='';
    my $total_hr=0.0;
    my $total_amount=0.0;
    my $amount=0.0;
    my $total_hours=0.0;
    my $row=0;

    unless(open(FD,"$file"))
    {
        &printError("Could not open file for reading: $file");
        return ('');
    }

    # get rate
    while (<FD>)
    {
        $line=$_;
        chomp($line);
        next if ($line =~ /^#/);

        if ($line =~ /(^_rate_=)(.*)/)
        {
            $rate=$2;
        }
        last if ($line =~ /^_data_/);
    }

    while (<FD>)
    {
        $row++;
        $line=$_;
        chomp($line);
        ($date,$from,$to,$comment)=split(/\t/,$line);
        if (! &verifyDate($date))
        {
            &printError("Could not verify date: $date in row $row,the format is m/d/y");
            close(FD);
            return;
        }
        if (! &verifyTimeString($from))
        {
            &printError("Could not verify from time: $from in row $row");
            close(FD);
            return;
        }
        if (! &verifyTimeString($to))
        {
            &printError("Could not verify to time: $to in row $row");
            close(FD);
            return;
        }


        my $tf=$from;
        my $tt=$to;

        $total_hr=timeDiffHours($tf,$tt);
        $total_hours += $total_hr;
        $amount=$total_hr*1.0*$rate;
        $total_amount += $amount*1.00;
        $total_amount=sprintf("%.2f",$total_amount);

my $tmpline=<<EOF;
<td nowrap valign="top">${date}</td>
<td valign="top">${comment}</td>
<td nowrap valign="top" align="right">${from}</td>
<td nowrap valign="top" align="right">${to}</td>
<td nowrap align="right" valign="top">${total_hr}</td>
EOF
;
        push(@report,$tmpline);

    }
    close(FD);

    $total_hours=sprintf("%.2f",$total_hours);
my $t=<<EOF;
<td bgolor="#a0b8c8" colspan=4 align="right"><b>Total Hours</b></td>
<td align="right">${total_hours}</td>
EOF
;
    push(@report,$t);

my $t=<<EOF;
<td bgolor="#a0b8c8" colspan=4 align="right"><b>Total amount \@${rate}/Hr</b></td>
<td align="right">\$ $total_amount</td>
EOF
;
    push(@report,$t);

    return (\@report);
}

##----
# toHour()
# from hour min sec
##----
sub toHour
{
    my $hr=shift;
    my $min=shift;
    my $sec=shift;

    my $min=$min/60.0;
    my $sec=$sec/3600.00;

    my $hr=$hr*1.00 + $min + $sec;

    return ($hr);
}

##-----
# editDataFile()
#------
sub editDataFile
{
    my $project=shift;
    my $file="${project_dir}/${project}/${project}.dat";
    my $trailer='';

    local *FD;

    if (! -f $file)
    {
        &printError("Data file \"$file\" does not exist");
        return;
    }

    unless (open(FD,$file))
    {
        &printError("Could not open file for reading: $file ($!)");
        return;
    }

    print $query->start_form(-action=>"$script_name/save_edited_data?project=$project");
    print <<EOF;
<table border=1 cellpadding=2 cellspacing=2>
<tr>
<td colspan=5 align="center" bgcolor="#a0b8c8">
<b>Edit Project <font color="#00ff00">$project</font> data</b>
</td>
</tr>
EOF
;
    my @lines=(<FD>);
    close(FD);
    my $line='';
    my $n=0;
    my $d=0;
    my $len=0;
    if (scalar(@lines))
    {
        my $ok=0;
        foreach $line (@lines)
        {
            chomp($line);
            if ($line =~ /^#/m)
            {
                print "<tr>\n";
                print "<td colspan=5 nowrap>\n";
                $n++;
                my $len=length($line);
                print "Comment:\n";
                print $query->textfield(-name=>"comment_${n}",
                        -size=>$len,
                        -default=>"$line");
                print "</td>\n";
                print "</tr>\n";
                next;
            }

            if ($line =~ /(^_rate_=)(.*)/)
            {
                $ok++;
                print "<tr>\n";
                print "<td colspan=5 nowrap>\n";
                print "Rate/Hr: ";
                print $query->textfield(-name=>"rate_text",
                        -size=>10,
                        -default=>"$2");

                print "</td>\n";
                print "</tr>\n";
                next;
            }
            elsif ($line =~ /_data_/)
            {
                $ok++;
                next;
            }
            else
            {
                if ($line =~ /^_trailer_/)
                {
                    $trailer=$line;
                    next;
                }
                my ($date,$from,$to,$comment)=split(/\t/,$line);
                my @all=();
                push(@all,$date);
                push(@all,$from);
                push(@all,$to);
                push(@all,$comment);

                if ($d == 0)
                {
print <<EOF;
<tr bgcolor="#dddddd">
    <td align="center">
    <font color="#000099">
    Delete
    </font>
    </td>
    <td align="center">
    <font color="#000099">
    Date
    </font>
    </td>
    <td align="center">
    <font color="#000099">
    From
    </font>
    </td>
    <td align="center">
    <font color="#000099">
    To
    </font>
    </td>
    <td align="center">
    <font color="#000099">
    Description
    </font>
    </td>
</tr>
EOF
;
                }
                print "<tr>\n";

                    print "<td align=\"center\">\n";
                    print $query->checkbox(-name=>"delete_$d",
                        -value=>'on',
                        -label=>'');
                    print "</td>\n";
                my $ncol=0;
                foreach (@all)
                {
                    $d++;
                    $ncol++;

                    $len=10 if ($ncol == 1);
                    $len=8 if ($ncol == 2);
                    $len=8 if ($ncol == 3);
                    $len=60 if ($ncol == 4);
                    $ncol=0 if ($ncol >= 4);

                    print "<td nowrap>\n";
                    print $query->textfield(-name=>"data_$d",
                        -size=>$len,
                        -default=>$_);
                    print "</td>\n";
                }
                print "</tr>\n";
            }

        }
        if ($d == 0) # no data
        {
            &printEmptyFields();
        }
    }
    print "<tr>\n";
    print "<td colspan=5 align=\"center\" bgcolor\"#cccccc\">\n";
    print $query->submit(-name=>'submit',-value=>'Submit');
    print "</td>\n";
    print "</tr>\n";



    print "</table>\n";
    print $query->end_form;

}

##-----
# verifyDate() of the form m/d/year
# return 1 if ok, 0 otherwise
##-----
sub verifyDate
{
    my $date=shift;
    if ($date !~ /([0-9]+)\/([0-9]+)\/([0-9]+)$/m)
    {
        return (0);
    }
    my $month=$1;
    my $day=$2;
    my $year=$3;
    if ($month <= 0 or $month > 12)
    {
        return (0);
    }
    if ($day <= 0 or $day > 31)
    {
        return (0);
    }

    if ($year < 0)
    {
        return (0);
    }

    return (1);
}

##-----
# verifyData()
#  arg is reference to an array
# returns 1 on OK, 0 therwise
##-----
sub verifyData
{
    my $all=shift;
    my @all=@$all;
    my $index;
    my $i=0;
    my $row=1;

    foreach $index (@all)
    {
        my $value=$query->param($index);
        if ($index =~ /comment_/)
        {
#            print "<code>$value</code><br>\n";
        }
        elsif ($index eq "rate_text")
        {
#            print "<code>_rate_=$value</code><br>\n";
#            print "<code>_data_</code><br>\n";
        }
        elsif ($index =~ /delete_/)
        {
            next;
        }
        elsif ($index =~ /data_/)
        {
            $i++;
            # verify date
            if ($i == 1) 
            {
                if (! &verifyDate($value))
                {
                    &printError("Could not verify date: <b>$value</b> in row $row,the format is m/d/y");
                    return (0);
                }
            }

            # verify From time
            if ($i == 2 or $i == 3)
            {
                if ($value !~ /(\d+):(\d+)\s+(.*)/m)
               {
                    &printError("Error parsing time: <b>$value</b>, in row $row, the format is hr:min am/pm, e.g <b>10:03 AM 5:00 PM</b>");
                    return (0);
                }
                my $hr=$1;
                my $min=$2;
                my $ampm=$3;
                if (! &verifyTime($hr,$min,$ampm))
                {
                    &printError("Could not verify time: $value in row $row");
                    return (0);
                }
            }

#            print "<code>$value\t";
            if ($i == 4)
            {
                $i=0;
                $row++;
#                print "</code><br>\n";
            }
        }
    }
    return (1);
}

##-----
# saveEditedData()
##-----
sub saveEditedData
{
    my @all=$query->param;
    my $index;
    my $i=0;
    my $project=$query->url_param('project');
    my $file="${project_dir}/${project}/${project}.dat";
    my $tmp_file="${file}.$$";
    my $del=0;
    my $cellc=0;
    my $on='';
    my $wrote_data_=0;

    local *WFD;

    unless (open(WFD,">${tmp_file}"))
    {
        &printError("Could not open file for writing: $file ($!)");
        return;
    }

    # verify date first
    if (! &verifyData(\@all))
    {
        &printError("Data verification failed");
        goto cleanup;
        return;
    }

    foreach $index (@all)
    {
        my $value=$query->param($index);
        if ($index =~ /comment_/)
        {
            print WFD "$value\n";
        }
        elsif ($index eq "rate_text")
        {
            print WFD "_rate_=$value\n";
            print WFD "_data_\n";
            $wrote_data_++;
        }
        elsif ($index =~ /delete_/)
        {
            next;
        }
        elsif ($index =~ /data_/)
        {
            if (! $wrote_data_)
            {
                print WFD "_rate_=100.00\n";
                print WFD "_data_\n";
                $wrote_data_++;
            }
            if ($i == 0)
            {
                $on=$query->param("delete_${cellc}");
            }
            $cellc++;
            $i++;
            if (! $on)
            {
                print WFD "$value\t";
            }
            if ($i == 4)
            {
                $i=0;
                if (! $on)
                {
                    print WFD "\n";
                }
            }
        }
    }
    close(WFD);
    if (rename($tmp_file,$file))
    {
        print "OK: Data Saved for project <font color=\"#000099\">$project</font><br>\n";
    }
    else
    {
        &printError("renaming $tmp_file - $file ($!)");
        goto cleanup;
    }
    &printForms();
    return;

cleanup:
    close(WFD);
    unlink($tmp_file);
}

##-----
# printEmptyFields()
##-----
sub printEmptyFields
{
print <<EOF;
<tr bgcolor="#dddddd">
    <td align="center">
    Delete
    </td>
    <td align="center">
    Date
    </td>
    <td align="center">
    From
    </td>
    <td align="center">
    To
    </td>
    <td align="center">
    Description
    </td>
</tr>
EOF
;
    my $i;
    print "<tr>\n";
    print "<td align=\"center\">\n";
    print "-\n";
     print "</td>\n";
    for ($i=0; $i < 4; $i++)
    {
        print "<td>\n";
        print $query->textfield(-name=>"data_$i",
            -size=>20);
        print "</td>\n";
    }
    print "</tr>\n";
} 

##----
# verifyTimeString()
# arg is of the form hr:min am/pm
#  returns 1 on OK, 0 otherwise
##----
sub verifyTimeString
{
    my $time=shift;
    if ($time !~ /(\d+):(\d+)\s+(.*)/m)
    {
        return (0);
    }
    my $hr=$1;
    my $min=$2;
    my $ampm=$3;

    return (&verifyTime($hr,$min,$ampm));

    return (1);
}

##-----
# verifyTime()
#  returns 1 on OK, 0 otherwise
##------
sub verifyTime
{
    my $hr=shift;
    my $min=shift;
    my $ampm=shift;

    if ($hr <= 0 or $hr > 12)
    {
        &printError("($hr:$min $ampm) Hour ($hr) must be in the range 1-12");
        return (0);
    }
    if ($min < 0 or $min > 59)
    {
        &printError("Minute ($min) must be in the range 0-59");
        return (0);
    }
    if ($ampm !~ /am|pm/i)
    {
        &printError("Time must end with AM or PM ($ampm)");
        return (0);
    }
    return (1);
}

##-----
# parseTime()
#  parse time in the format hr:min am/pm
# returns 1 on ok, 0 on error
#-----
sub parseTime
{
    my $time=shift;
    if (! $time)
    {
        print STDERR "No time specified\n";
        return (0);
    }

    if ($time !~ /(\d+):(\d+)\s+(.*)/m)
    {
        print STDERR "Could not parse time $time, the format is hr:min am/pm, e.g 10:03 am 5:00 pm\n";
        return (0);
    }
    return (1);
}

##-----
# TimeDiffHours
#  Takes 2 times as args and sends the difference between them in Hours
#  The args must be in the format  hr:min AM/PM
#  On success returns a number >= 0.0, or return -1 in case of error
##-----
sub timeDiffHours
{
    my $time1=shift;
    my $time2=shift;
    my $diff_hrs=0.0;

    if ($time1 !~ /(\d+):(\d+)\s+(.*)/m)
    {
        print "Error parsing: $time1, the format is hr:min am/pm, e.g 10:03 am 5:00 pm\n";
        return (-1);
    }
    my $hr1=$1;
    my $min1=$2;
    my $ampm1=$3;

    return (-1.0) if (! &verifyTime($hr1,$min1,$ampm1));

    if ($hr1 == 12 && $ampm1 =~ /am/i)
    {
        $hr1 = 12 - $hr1;
    }

    if ($ampm1 =~ /pm/i and $hr1 < 12)
    {
        $hr1 +=12;
    }

    
    if ($time2 !~ /(\d+):(\d+)\s+(.*)/m)
    {
        print "Error parsing: $time2, the format is hr:min am/pm, e.g 10:03 am 5:00 pm\n";
        return (-1);
    }
    my $hr2=$1;
    my $min2=$2;
    my $ampm2=$3;
    return (-1.0) if (! &verifyTime($hr2,$min2,$ampm2));


    if ($hr2 == 12 && $ampm2 =~ /am/i)
    {
        $hr2 = 12 - $hr2;
    }


    if ($ampm2 =~ /pm/i && $hr2 < 12)
    {
        $hr2 +=12;
    }

    if ($ampm1 =~ /am/i and $ampm2 =~ /am/i)
    {
        if ($hr1 > $hr2)
        {
            print "Err: From hour ($hr1) is > To hour ($hr2), it can't be\n";
            return (-1);
        }
    }
    if ($ampm1 =~ /pm/i and $ampm2 =~ /pm/i)
    {
        if ($hr1 > $hr2)
        {
            print "Err: From hour ($hr1) is > To hour ($hr2), it can't be\n";
            return (-1);
        }
    }




    my $start_secs=timelocal(0,$min1,$hr1,23,8,2001);
    my $end_secs=timelocal(0,$min2,$hr2,23,8,2001);
    my $diff=$end_secs-$start_secs;
    $diff_hrs=$diff/3600.0;

    if ($diff_hrs < 0.0)
    {
        $diff_hrs=24.0 + $diff_hrs;
    }
    $diff_hrs=sprintf("%.2f",$diff_hrs);

    return ($diff_hrs);
}

###----
# restoreProjectsForm()
# go through the removed directory and see if there's any marked deleted
# projects there
##-----
sub restoreProjectsForm
{
    my $removed_dir="${project_dir}/removed";
    my @marked_files=();
    my $files;
    if (! -d $removed_dir)
    {
        &printError("No projects found to be restored (1)");
        return;
    }

    $files=&getMarkedDeletedProjects();
    if (! $files)
    {
        &printError("No projects found to be restored (2)");
        return;
    }
    @marked_files=@$files;
    my $elem=scalar(@marked_files);
    if ($elem <= 0)
    {
        &printError("No projects found to be restored (3)");
        return;
    }

    print $query->start_form(-action=>"$script_name/unremove_project");

    print "<table border cellpadding=2 cellspacing=1>\n";
    print "<tr>\n";
    print "<td align=\"center\" bgcolor=\"#a0b8c8\">\n";
    print "<b>Projects to restore</b>\n";
    print "</td>\n";
    print "</tr>\n";

    print "<tr>\n";
    print "<td>\n";
    print $query->scrolling_list(-name=>'unremove',
            -values=>\@marked_files);
    print "</td>\n";
    print "</td>\n";

    print "<tr>\n";
    print "<td align=\"center\">\n";
    print $query->submit(-name=>'submit',-value=>'Restore Project');
    print "</td>\n";
    print "</tr>\n";



    print "</table>\n";
    print $query->end_form;
}

##----
# getMarkedDeletedProjects()
#   opens the $project_dir/removed,directory, finds all the files insude
#   and put the filenames in an array and returns reference to an array 
##----
sub getMarkedDeletedProjects
{
    local
        *DIR;

    my @files=();
    my @marked_files=();

    my $removed_dir="${project_dir}/removed";

    if (! opendir(DIR,$removed_dir))
    {
            &printError("Could not open directory: $removed_dir ($!)");
            return('');
    }

    @files=readdir(DIR);
    closedir(DIR);

    my $file;
    foreach $file (@files)
    {
        next if $file eq '.';
        next if $file eq '..';
        push(@marked_files,$file);
    }

    return (\@marked_files);
}

##-----
# restoreProject()
##-----
sub restoreProject
{
    my $file=$query->param('unremove');
    my $file_path='';
    my $file_base='';
    my $to_path='';
    my $pdir;

    $file_base=$file;
    $file_base =~ s/_[0-9]+$//g;

    $pdir="${project_dir}/${file_base}";
    $file_path="${project_dir}/removed/${file}";
    if (! -f $file_path)
    {
        &printError("File: $file_path does not exist");
        return;
    }


    if (! -d $pdir)
    {
        if (!mkdir($pdir,0700))
        {
            &printError("Could not make project directory: $pdir ($!)");
            return;
        }
    }
    $to_path="${pdir}/${file_base}.dat";
    if (-f  $to_path)
    {
        &printError("Unable to restore project: $file_base, thre's already a project exists by that name");
        &printForms();
        return;
    }
    if (! rename($file_path,$to_path))
    {
        &printError("Could not rename: $file_path to $to_path");
        return;
    }
    print<<EOF;
<font color=\"#00ff00\"><b>OK:</b></font> 
Project <font color="#000099">$file_base</font> restored
EOF
;
    &printForms();
}

##-----
# aboutTimeTrack
##-----
sub aboutTimeTrack
{
print<<EOF;
TimeTrack.pl - v $version_s<br>
TimeTrack.pl - a Perl CGI for keeping track of your personal projects.
<br>
Author: <a href="http://www.muquit.com/">Muhammad A Muquit</a>
<p>
Homepage:
<a href="http://www.muquit.com/muquit/software/TimeTrack_pl/TimeTrack_pl.html">
http://www.muquit.com/muquit/software/TimeTrack_pl/TimeTrack_pl.html</a>
<p>
<b>Copyright</b><br>
<pre>
It's a freeware. Do whatever you like with it. It would be nice but not 
required if you give me the credit for it. 

THIS PROGRAM IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. THE
AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE
AUTHOR Muhammad A. Muquit BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS
ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE. 
</pre>

EOF
;
}

##-----
# verifyProject()
#  return 1 if project is found, 0 otherwise
##-----
sub verifyProject
{
    my $project=shift;
    if (! $project)
    {
        return (0);
    }

    return (1);
}
